Skip to content

Conversation

@californiandreamer
Copy link

@californiandreamer californiandreamer commented Sep 9, 2025

Summary

  • Adds public iOS API stopReactNative() to deallocate the React Native runtime created by RCTReactNativeFactory and allow clean re‑initialization later. Fixes #134.
  • Old Architecture: calls bridge.invalidate() to tear down JS and native modules.
  • New Architecture: releases the runtime by dropping strong references (no public stop API on RCTHost).
  • Prevents crashes when pushing a React Native screen after stopping.
  • Removes stale lazy caching of rootViewFactory to avoid retaining the old runtime.
  • Documentation updates for the new API and usage:
    • docs/SWIFT.md
    • docs/OBJECTIVE_C.md
  • Backwards compatible: existing startReactNative() API remains; view() now self‑heals if RN was previously stopped.

Test plan

  • Press the “Stop React Native” (to check app won't crash if stopReactNative called before RN was initialize)
  • Push RN screen → pop → tap the “Stop React Native” button → push again (no crash).
  • Repeat with both architectures toggled.
  • Watch the Xcode Instruments graph to confirm RN objects are released after stop (RSS may not drop immediately).

Note

Adds an iOS stopReactNative() API to tear down the RN runtime, simplifies factory creation/usage, and updates docs and the Swift example.

  • iOS SDK (ios/ReactNativeBrownfield.swift):
    • New API: stopReactNative() invalidates the bridge, removes observers, and clears the factory; safe to call multiple times.
    • Factory lifecycle: Replaces cached rootViewFactory with a lazy factory creator; view(...) now resolves via factory; startReactNative(..., launchOptions:) simplified.
  • Docs:
    • Add stopReactNative reference, description, and examples in docs/SWIFT.md and docs/OBJECTIVE_C.md.
  • Example app (example/swift/App.swift):
    • Add "Stop React Native" button calling ReactNativeBrownfield.shared.stopReactNative(); minor UI tweaks.

Written by Cursor Bugbot for commit aab1339. This will update automatically on new commits. Configure here.

Copy link
Member

@okwasniewski okwasniewski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for working on this! 🚀

Overall looks good, left couple of questions.

cursor[bot]

This comment was marked as outdated.

cursor[bot]

This comment was marked as outdated.

@californiandreamer californiandreamer force-pushed the feat/add-deallocate-method-ios branch 2 times, most recently from c11f9c0 to 5bef4b4 Compare September 24, 2025 19:17
@californiandreamer
Copy link
Author

californiandreamer commented Sep 24, 2025

@okwasniewski, I refactored the factory a bit and added some additional checks due to Cursor Bugbot comments.

When it comes to the stopReactNative() call on the RN screen, the app is not crashing but just goes white screen. We can think about a bit better fallback. I spent some time on that and didn't find a solution yet. Will dig deeper 😄

Simulator.Screen.Recording.-.iPhone.16.Pro.-.2025-09-24.at.22.52.53.mp4

@okwasniewski
Copy link
Member

@californiandreamer This looks like a expected behavior if you stop react native, let's ship it.

return
}

guard let factory = reactNativeFactory else {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: guard let reactNativeFactory else

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would skip for now. The guard let reactNativeFactory else would shadow the property with a let, preventing the later reactNativeFactory = nil reset in this method

@californiandreamer californiandreamer force-pushed the feat/add-deallocate-method-ios branch from 5bef4b4 to aab1339 Compare November 14, 2025 18:29
@californiandreamer
Copy link
Author

@okwasniewski I force pushed the updated version of my commits due to the last changes in the rootViewFactory, addressing your comment regarding extra notification dispatch.

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR is being reviewed by Cursor Bugbot

Details

Your team is on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle for each member of your team.

To receive Bugbot reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

* @param launchOptions Launch options, typically passed from AppDelegate.
*/
@objc public func startReactNative(onBundleLoaded: (() -> Void)?, launchOptions: [AnyHashable: Any]?) {
storedLaunchOptions = launchOptions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Late Option Updates Cause React Native Inconsistency

The storedLaunchOptions assignment happens before the guard check that returns early if reactNativeFactory already exists. This allows launch options to be modified after React Native initialization, potentially causing inconsistent state when view() uses the updated options with an already-initialized factory.

Fix in Cursor Fix in Web

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add method to deallocate reactNativeFactory instance

2 participants